<?php

namespace Simanx\Spes\Loader;

use Illuminate\Support\Facades\Route;
use Simanx\Spes\Attribute\ClassAttributeProxy;
use Simanx\Spes\Attribute\Route\Attributes\RouteMethod;
use Simanx\Spes\Attribute\Route\Attributes\Router;
use Simanx\Spes\Attribute\Route\Permission\Attributes\Can;

/**
 * 路由Attribute加载器
 * @package Simanx\Spes\Route
 */
class RouteLoader extends Loader
{
    public function load(): void
    {
        if ($this->app->routesAreCached()) {
            return;
        }

        foreach ($this->classes() as $class) {
            $routerClassAttribute = ClassAttributeProxy::create($class);
            /** @var Router $classRouteAttr */
            $classRouteAttr = $routerClassAttribute->getAttribute(Router::class);
            if (!$classRouteAttr) {
                continue;
            }

            $routeAttributes = $routerClassAttribute->getMethodAttributes(RouteMethod::class);
            if (!$routeAttributes) {
                continue;
            }

            $permissionClassAttribute = ClassAttributeProxy::create($class);
            /** @var Can $rootPermissionAttribute */
            $rootPermissionAttribute = $permissionClassAttribute->getAttribute(Can::class);
            $permissionPrefix = '';
            if ($rootPermissionAttribute) {
                $permissionPrefix = $rootPermissionAttribute->permission;
            }

            Route::group([
                'prefix' => $classRouteAttr->path,
                'middleware' => $classRouteAttr->middleware
            ], function () use ($permissionClassAttribute, $routeAttributes, $routerClassAttribute, $classRouteAttr, $permissionPrefix) {
                /** @var RouteMethod $routeAttribute */
                foreach ($routeAttributes as $method => $attributes) {
                    $routeAttribute = $attributes[0] ?? null;
                    if (!$routeAttribute) {
                        continue;
                    }

                    $middleware = $routeAttribute->middleware;
                    /** @var Can $ability */
                    $ability = $permissionClassAttribute->getAttributeFromMethod($method, Can::class);
                    if ($ability) {
                        $middleware[] = 'spes.can:__SPES__,' . ($permissionPrefix ? $permissionPrefix . '.' : '') . $ability->permission;
                    }

                    $routeName = $this->routeName($classRouteAttr->name, $routeAttribute->name);
                    Route::addRoute(
                        $routeAttribute->getMethod(),
                        $routeAttribute->path,
                        array_merge([
                            'uses' => sprintf('%s@%s', $routerClassAttribute->getClassName(), $method),
                            'middleware' => $middleware,
                            'as' => $routeName
                        ], $routeAttribute->action)
                    );
                }
            });
        }
    }

    private function routeName($classRouteName, $methodRouteName): string
    {
        if ($classRouteName) {
            if ($methodRouteName) {
                return sprintf('%s.%s', $classRouteName, $methodRouteName);
            }

            return $classRouteName;
        }

        return $methodRouteName;
    }
}